'use client'; import { use, useEffect, useRef, useState } from 'react'; import { useDonationHub } from '@/hooks/useDonationHub'; import { fetchApi } from '@/lib/utils/client'; import './style.scss'; type Props = { params: Promise<{ widgetToken: string }>; searchParams: Promise<{ [key: string]: string|string[]|undefined }>; }; type RankListResponse = { list: { rank: number; sponsorMemberID: number; sponsorName: string; totalAmount: number; donationCount: number }[]; }; type RankStyleConfig = { id: number; title: string; theme: number; period: number; isShowAmount: boolean; maxRankCount: number; titleFontFamily: string|null; titleFontSizePx: number; titleFontColor: string; rank1FontFamily: string|null; rank1FontSizePx: number; rank1FontColor: string; rank2FontFamily: string|null; rank2FontSizePx: number; rank2FontColor: string; rank3FontFamily: string|null; rank3FontSizePx: number; rank3FontColor: string; isShowDonationCount: boolean; isActive: boolean; }; export default function RankPage({ params, searchParams }: Props) { const { widgetToken } = use(params); const sp = use(searchParams); const configID = typeof sp.configID === 'string' ? parseInt(sp.configID, 10) : null; const hubUrl = process.env.NEXT_PUBLIC_API_URL + '/hubs/donation'; const { ranking, setRanking } = useDonationHub(widgetToken, hubUrl); const [styleCfg, setStyleCfg] = useState(null); const widgetRef = useRef(null); // 스타일 config 로드 useEffect(() => { const qs = configID ? `?configID=${configID}` : ''; fetchApi(`/api/widget/rank/config/${widgetToken}${qs}`, { silent: true }).then(res => { if (res.data) { setStyleCfg(res.data); } }).catch(() => {}); }, [widgetToken, configID]); // 순위 데이터 로드 useEffect(() => { const qs = configID ? `?configID=${configID}` : ''; fetchApi(`/api/widget/rank/by-token/${widgetToken}${qs}`, { silent: true }).then(res => { if (res.data?.list) { setRanking(res.data.list); } }).catch(() => {}); }, [widgetToken, configID, setRanking]); // CSS variables 적용 useEffect(() => { if (!widgetRef.current) { return; } const el = widgetRef.current; el.style.setProperty('--rank-title-font-family', styleCfg?.titleFontFamily ?? 'inherit'); el.style.setProperty('--rank-title-font-size', `${styleCfg?.titleFontSizePx ?? 18}px`); el.style.setProperty('--rank-title-color', styleCfg?.titleFontColor ?? '#FFFFFF'); el.style.setProperty('--rank-1-font-family', styleCfg?.rank1FontFamily ?? 'inherit'); el.style.setProperty('--rank-1-font-size', `${styleCfg?.rank1FontSizePx ?? 15}px`); el.style.setProperty('--rank-1-color', styleCfg?.rank1FontColor ?? '#FFD700'); el.style.setProperty('--rank-2-font-family', styleCfg?.rank2FontFamily ?? 'inherit'); el.style.setProperty('--rank-2-font-size', `${styleCfg?.rank2FontSizePx ?? 15}px`); el.style.setProperty('--rank-2-color', styleCfg?.rank2FontColor ?? '#C0C0C0'); el.style.setProperty('--rank-3-font-family', styleCfg?.rank3FontFamily ?? 'inherit'); el.style.setProperty('--rank-3-font-size', `${styleCfg?.rank3FontSizePx ?? 15}px`); el.style.setProperty('--rank-3-color', styleCfg?.rank3FontColor ?? '#CD7F32'); }, [styleCfg]); const title = styleCfg?.title ?? '후원 순위'; const isShowAmount = styleCfg?.isShowAmount ?? true; const isShowCount = styleCfg?.isShowDonationCount ?? false; return (
{title}
{ranking.map(item => { const badgeClass = item.rank <= 3 ? `badge-${item.rank}` : 'badge-default'; return (
{item.rank}
{item.sponsorName}
{isShowAmount && (
{item.totalAmount.toLocaleString()}원 {isShowCount && ` (${item.donationCount}회)`}
)}
); })}
); }